package com.yuexi.domain.payment.alipay;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeCancelResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePayResponse;
import com.yuexi.domain.payment.alipay.bo.AliPayBO;
import com.yuexi.domain.payment.alipay.definds.TradeStatus;
import com.zenx.domain.Entity;
import lombok.extern.slf4j.Slf4j;

import java.util.regex.Pattern;

/**
 * @author jie
 * @date 2023/4/10 -11:38
 */
@Slf4j
@Entity
public class AliPayDomain {

    private String matchAuthCodeRegex = "^(2[5-9]|30)\\d{14,22}$";

    /**
     * 验证authCode是否正确
     * 规则：（25~30开头的长度为16~24位的数字）
     */
    public boolean verifyAuthCode(String authCode) {
        return Pattern.matches(matchAuthCodeRegex, authCode);
    }

    /**
     * 支付
     */
    public AlipayTradePayResponse pay(AliPayBO payBO) throws Exception {

        return Factory.Payment.FaceToFace()
                .pay(payBO.getSubject(), payBO.getOutTradeNo(), payBO.getTotalAmount(), payBO.getAuthCode());
    }

    /**
     * 支付
     */
    public void payTry(AliPayBO payBO) {
        try {
            AlipayTradePayResponse response = this.pay(payBO);
            if (ResponseChecker.success(response)) {
                log.info("调用成功");
            } else {
                throw new RuntimeException("调用失败，原因：" + response.msg + "，" + response.subMsg);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 查询订单
     */
    public AlipayTradeQueryResponse query(String outTradeNo) throws Exception {
        return Factory.Payment.Common()
                .query(outTradeNo);
    }

    /**
     * 退款
     */
    public AlipayTradeRefundResponse refund(String outTradeNo, String refundAmount) throws Exception {
        return Factory.Payment.Common()
                .refund(outTradeNo, refundAmount);
    }

    /**
     * 退款，内部处理异常消息
     */
    public void refundTry(String outTradeNo, String refundAmount) {
        try {
            AlipayTradeRefundResponse response = this.refund(outTradeNo, refundAmount);
            if (ResponseChecker.success(response)) {
                log.info("调用成功");
            } else {
                throw new RuntimeException("调用失败，原因：" + response.msg + "，" + response.subMsg);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 撤单
     */
    public AlipayTradeCancelResponse cancel(String outTradeNo) throws Exception {
        return Factory.Payment.Common()
                .cancel(outTradeNo);
    }

    /**
     * 撤单
     */
    public void cancelTry(String outTradeNo) {
        try {
            AlipayTradeCancelResponse response = this.cancel(outTradeNo);
            if (ResponseChecker.success(response)) {
                log.info("调用成功");
            } else {
                throw new RuntimeException("调用失败，原因：" + response.msg + "，" + response.subMsg);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 轮询查询订单状态
     *
     * @param outTradeNo    外部订单号
     * @param attemptNumber 尝试次数
     * @return true说明订单支付成功
     */
    public boolean attemptQueryOrder(String outTradeNo, int attemptNumber) {
        for (int i = 0; i < attemptNumber; i++) {
            try {
                AlipayTradeQueryResponse response = this.query(outTradeNo);
                log.debug("尝试次数：" + attemptNumber + ", response: " + JSON.toJSONString(response));
                if (ResponseChecker.success(response) && TradeStatus.isTradeSuccess(response.getTradeStatus())) {
                    log.info("调用成功");
                    return true;
                } else {
                    // 如果是未知状态
                    if (TradeStatus.isUnknownState(response.getTradeStatus())) {
                        Thread.sleep(3000);
                        continue;
                    } else {
                        throw new RuntimeException("调用失败，原因：" + response.msg + "，" + response.subMsg);
                    }
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
        }
        return false;
    }
}
